home *** CD-ROM | disk | FTP | other *** search
-
- /*
- File: LayoutEditLibrary.c
-
- Contains: graphics libraries - simple layout editing based on the TextEdit model
-
- Written by: Dave Opstad, Eric Mader
-
- Copyright: © 1995 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <6> 6/26/95 TD fixing up protos
- <5> 5/4/95 JD updating GetEnvirons to GetScriptManagerVariable (yup, I get
- paid for this…)
- <4> 4/7/95 jtd removing unused variables from routines
- <3> 1/24/95 JD updated to latest GX 1.1 source (as of 16 Jan 1995)
- <2> 1/9/95 JD changed 'boolean' to 'Boolean'
- <1> 1/9/95 JD First checked in.
- */
-
- #include <Types.h>
- #include <Memory.h>
- #include <Events.h>
- #include <OSUtils.h>
- #include <Scrap.h>
- #include <Script.h>
- #include <GXTypes.h>
- #include <GXLayout.h>
- #include <GXGraphics.h>
- #include <GXEnvironment.h>
- #include "SelectionLibrary.h"
- #include "GraphicsLibraries.h"
- #include "StorageLibrary.h"
- #include "LayoutEditLibrary.h"
-
-
- #define LockHandle(handle) (HLock ((Handle)handle), *handle)
- #define UnlockHandle(handle) HUnlock ((Handle)handle)
-
- #define LockEditHandle(handle) (LayoutEditPtr) LockHandle(handle)
- #define UnlockEditHandle(handle) UnlockHandle(handle)
-
- #define MIN(a,b) ((a) < (b)? (a): (b))
- #define MAX(a,b) ((a) > (b)? (a): (b))
-
- #define maxRanges 10
- #define textBufferLength 16
- #define nextUpdateDelta 5
-
- #define layoutOutOfDate 0x8000
- #define highlightOutOfDate 0x4000
- #define highlightBlinks 0x2000
- #define highlightIsBlinking 0x1000
-
- #define BOUNDS 0
-
- enum
- {
- backSpace = 8,
- leftArrow = 0x1C,
- rightArrow,
- upArrow,
- downArrow
- };
-
- typedef unsigned long ulong;
- typedef unsigned short ushort;
-
- /*
- The LayoutEditRecord contains the layout and highlight shapes,
- the selection. flags contains flags which indicate that the
- layout and highlight shapes haven't been rebuilt since their
- corresponding data in the LayoutEditRecord has been changed.
-
- nextUpdate time, if non-zero tells the idle routine when to
- update and re-draw the layout gxShape.
-
- selectionRanges is working storage used for manipulating the
- layout's selection. NOTE: the actual handle containing the
- LayoutEditRecord will be large enough to contain the
- SelectionOffsetRange array which immediately follows selectionRanges.
- */
- typedef struct {
- short flags;
- short highlightHideCount;
- short oldScript;
- SelectionOffset synchOffset;
- gxShape layout;
- gxShape eraser;
- gxShape highlight;
-
- #if BOUNDS
- gxShape bounds;
- gxShape boundsEraser;
- #endif
-
- SelectionHandle selection;
- gxShape scrap;
- ulong nextUpdateTime;
- ulong nextBlinkTime;
- long deleteStartOffset;
- long deleteEndOffset;
- gxStyle insertionStyle;
- short insertionLevel;
- short textBufferOffset;
- char textBuffer[textBufferLength];
- SelectionRanges selectionRanges;
- } LayoutEditRecord, *LayoutEditPtr;
-
-
- /*
- I N T E R N A L R O U T I N E S
- */
-
-
- /*
- Draw the part of the layout which has changed.
- */
- static void DrawDifference(LayoutEditPtr layout)
- {
- GXDrawShape(layout->eraser);
-
- #if BOUNDS
- GXDrawShape(layout->boundsEraser);
- #endif
-
- GXDrawShape(layout->layout);
-
- #if BOUNDS
- GXDrawShape(layout->bounds);
- #endif
- }
-
- /*
- Synch the keyboard to the font at the new selection.
- */
- static void SynchKeyboard(LayoutEditPtr layout)
- {
- long styleRuns;
- gxStyle selectionStyle;
- gxFontPlatform platform;
- gxFontScript script;
- gxFontLanguage language;
-
- GXGetLayoutParts(
- layout->layout,
- layout->synchOffset, layout->synchOffset,
- nil,
- &styleRuns, nil, &selectionStyle,
- nil, nil, nil);
-
- if (styleRuns == 0 || selectionStyle == nil)
- selectionStyle = GXGetShapeStyle(layout->layout);
-
- platform = GXGetStyleEncoding(selectionStyle, &script, &language);
-
- switch (platform)
- {
- case gxUnicodePlatform:
- break;
-
- case gxMacintoshPlatform:
- if (script == gxNoScript)
- script = smRoman;
- else
- script -= 1;
-
- if (language != gxNoLanguage && GetScriptVariable((short) script, smScriptLang) != language - 1)
- SetScriptVariable((short) script, smScriptLang, language - 1);
-
- if (GetScriptManagerVariable(smKeyScript) != script)
- KeyScript((short) script);
- break;
-
- default:
- break;
- }
- }
-
- /*
- Make sure the caret is not blinked out.
- */
- static void ResetCaret(LayoutEditPtr layout)
- {
- layout->nextBlinkTime = TickCount() + GetCaretTime();
- if ((layout->flags & highlightBlinks) && (layout->flags & highlightIsBlinking))
- {
- layout->flags ^= highlightIsBlinking;
- if (--layout->highlightHideCount == 0)
- GXDrawShape(layout->highlight);
- }
- }
-
- /*
- Build a selection from start to end. If start and end are equal,
- the selection will be a caret.
- */
- static void NewSelection(LayoutEditPtr layout, SelectionOffset start, SelectionOffset end)
- {
- layout->selectionRanges.rangeCount = 1;
- layout->selectionRanges.ranges[0].minOffset = start;
- layout->selectionRanges.ranges[0].maxOffset = end;
-
- if (layout->selection)
- DisposeSelection(layout->selection);
-
- layout->selection = NewRangeSelection(&layout->selectionRanges.ranges[0]);
-
- layout->synchOffset = start;
- layout->flags |= highlightOutOfDate;
- }
-
- /*
- Update the layout's highlight gxShape if the selection's
- changed since we last built it.
- */
- static void UpdateHighlight(LayoutEditPtr layout)
- {
- if (layout->flags & highlightOutOfDate)
- {
- DisposeShapeAt(&layout->highlight);
-
- layout->highlight = GetLayoutSelection(
- layout->layout,
- layout->selection,
- 0,
- gxHighlightAverageAngle,
- gxSplitCaretType);
-
- if (GetSelectionType(layout->selection) == simpleCaret)
- {
- SetShapeFastXorTransfer(layout->highlight, nil, nil);
- layout->flags |= highlightBlinks;
- }
- else
- {
- SetShapeCommonTransfer(layout->highlight, gxHighlightMode);
- SetShapeCommonColor(layout->highlight, gxWhite);
-
- layout->flags &= ~highlightBlinks;
- if (layout->flags & highlightIsBlinking)
- {
- layout->flags ^= highlightIsBlinking;
- --layout->highlightHideCount;
- }
- }
-
- DisposeStyleAt(&layout->insertionStyle);
- layout->insertionLevel = -1;
-
- SynchKeyboard(layout);
- layout->flags &= ~highlightOutOfDate;
- }
- }
-
- /*
- Build a new selection from start to end, and a new highlight gxShape
- that matches it.
- */
- static void NewSelectionAndHighlight(
- LayoutEditPtr layout,
- SelectionOffset start,
- SelectionOffset end)
- {
- NewSelection(layout, start, end);
- UpdateHighlight(layout);
- }
-
- /*
- Return the offset of the glyph before the one at the specified
- offset in the layout's text.
- */
- static SelectionOffset GetPreviousOffset(gxShape layout, SelectionOffset offset)
- {
- ushort firstGlyph, secondGlyph;
- gxLayoutOffsetState offsetState;
- static SelectionOffset offsetStateSizes[] = {1, 1, 2, 2, 0};
-
- GXGetOffsetGlyphs(layout, offset, 0, &offsetState, &firstGlyph, &secondGlyph);
-
- return offset - offsetStateSizes[offsetState & ~gxOffsetInsideLigature];
- }
-
- /*
- Delete the text from the layout in the range specified by pRange.
- */
- static void DeleteRange(LayoutEditPtr layout, SelectionOffsetRange *pRange)
- {
- if (layout->deleteStartOffset < 0)
- layout->deleteEndOffset = pRange->maxOffset;
-
- layout->deleteStartOffset = pRange->minOffset;
- layout->flags |= layoutOutOfDate;
- }
-
-
- /*
- Delete the selected text from the layout. If the selection is a
- caret, delete the character before the caret. Change the selection
- to a caret just before the old selection.
- */
-
- static void DeleteSelection(LayoutEditPtr layout)
- {
- SelectionType selectionType = GetSelectionType(layout->selection);
- SelectionOffset newCaret;
-
- switch (selectionType)
- {
- case emptySelection:
- newCaret = 0;
- break;
-
- case simpleCaret:
- {
- SelectionOffset caret = GetCaretSelection(layout->selection, nil);
-
- if(layout->textBufferOffset)
- {
- layout->textBufferOffset -= 1;
- newCaret = caret - 1;
- }
- else if (caret > 0)
- {
- SelectionOffsetRange range;
- SelectionOffset previous = GetPreviousOffset(layout->layout, caret);
-
- range.minOffset = newCaret = previous;
- range.maxOffset = caret;
- DeleteRange(layout, &range);
- }
- else newCaret = caret;
-
- break;
- }
-
- case simpleRange:
- case discontiguousRange:
- {
- long rangeCount;
- SelectionRanges *ranges = &layout->selectionRanges;
- SelectionOffsetRange *pRange;
-
- (void) GetRangeSelection(layout->selection, ranges);
- rangeCount = ranges->rangeCount;
- pRange = &ranges->ranges[rangeCount];
-
- /*
- go through the ranges backwards to save sliding stuff
- that'll get deleted later and so that the caret is set
- for the first range.
- */
- while (--rangeCount >= 0)
- {
- DeleteRange(layout, --pRange);
- newCaret = pRange->minOffset;
- }
-
- break;
- }
-
- }
-
- /* set layout's selection to a caret before the deletion */
- NewSelection(layout, newCaret, newCaret);
- ResetCaret(layout);
- }
-
- /*
- Make sure the handle is at least newSize bytes long;
- If it isn't, grow it to be newSize + extra.
- */
- static Ptr GrowAndLockHandle(Handle handle, Size newSize, Size extra)
- {
- Size oldSize = GetHandleSize(handle);
-
- if (oldSize < newSize)
- SetHandleSize(handle, newSize + extra);
-
- return LockHandle(handle);
- }
-
- #if BOUNDS
- static void SetBounds(LayoutEditPtr layout)
- {
- gxRectangle bounds;
-
- GXGetShapeTypographicBounds(layout->layout, &bounds);
- GXSetRectangle(layout->bounds, &bounds);
- GXIgnoreGraphicsNotice(transform_already_set);
- GXSetShapeTransform(layout->bounds, GXGetShapeTransform(layout->layout));
- GXPopGraphicsNotice();
- }
- #endif
-
- static void SetEraser(LayoutEditPtr layout)
- {
- layout->eraser = GXCopyToShape(layout->eraser, layout->layout);
- SetShapeCommonColor(layout->eraser, gxWhite);
-
- #if BOUNDS
- layout->boundsEraser = GXCopyToShape(layout->boundsEraser, layout->bounds);
- SetShapeCommonColor(layout->boundsEraser, gxWhite);
- #endif
- }
-
- /*
- If the backing store in the LayoutEditRecord has changed since
- the layout gxShape was last built, rebuild the layout.
- */
- static void UpdateLayout(LayoutEditPtr layout)
- {
- if (layout->flags & layoutOutOfDate)
- {
- void *textBuffer = &layout->textBuffer, **text = nil;
- short *levels = nil, levelRunCount = 0, styleRunCount = 0, textRunCount = 0,
- *textRunLength = nil, *styleRunLength = nil, *levelRunLength = nil;
- gxStyle *styles = nil;
-
- SetEraser(layout);
-
- if (layout->textBufferOffset)
- {
- text = &textBuffer;
- textRunLength = &layout->textBufferOffset;
- textRunCount = 1;
-
- if (layout->insertionStyle)
- {
- styles = &layout->insertionStyle;
- styleRunLength = textRunLength;
- styleRunCount = 1;
- }
-
- if (layout->insertionLevel >= 0)
- {
- levels = &layout->insertionLevel;
- levelRunLength = textRunLength;
- levelRunCount = 1;
- }
- }
-
- /* edit the layout */
- GXSetLayoutParts(
- layout->layout,
- layout->deleteStartOffset,
- layout->deleteEndOffset,
- textRunCount,
- textRunLength,
- (const void **) text,
- styleRunCount,
- styleRunLength,
- styles,
- levelRunCount,
- levelRunLength,
- levels);
-
- #if BOUNDS
- SetBounds(layout);
- #endif
-
- /* erase the old layout and draw the new one */
- DrawDifference(layout);
-
- layout->flags &= ~layoutOutOfDate;
- layout->nextUpdateTime = 0;
- layout->textBufferOffset = 0;
- layout->deleteStartOffset = -1;
- layout->insertionLevel = -1;
- DisposeStyleAt(&layout->insertionStyle);
- }
- }
-
- /*
- Add a character to the layout at the selection. This routine
- assumes that the selection is a caret; i.e. if it was a range,
- the range has been deleted leaving a caret.
- */
- static void InsertByte(LayoutEditPtr layout, char byte)
- {
- SelectionOffset caret;
-
- caret = layout->selectionRanges.ranges[0].minOffset;
-
- if (layout->textBufferOffset >= textBufferLength)
- UpdateLayout(layout);
-
- if (layout->deleteStartOffset < 0)
- layout->deleteStartOffset = layout->deleteEndOffset = caret;
-
- layout->textBuffer[layout->textBufferOffset++] = byte;
-
- /* set selection to a caret after the new byte */
- NewSelection(layout, caret + 1, caret + 1);
- ResetCaret(layout);
-
- layout->flags |= layoutOutOfDate;
- }
-
- /*
- If the highlight gxShape isn't already hidden, erase
- it by drawing it on top of itself.
- */
- static void HideHighlight(LayoutEditPtr layout)
- {
- if (layout->highlightHideCount++ == 0)
- GXDrawShape(layout->highlight);
- }
-
- /*
- If the highlight gxShape isn't already visible, update it
- and draw it.
- */
- static void ShowHighlight(LayoutEditPtr layout)
- {
- if (--layout->highlightHideCount <= 0)
- {
- UpdateHighlight(layout);
- GXDrawShape(layout->highlight);
- layout->highlightHideCount = 0;
- }
- }
-
- /*
- Draw the highlight shape (if it's visible).
- */
- static void DrawHighlight(LayoutEditPtr layout)
- {
- if (layout->highlightHideCount <= 0)
- GXDrawShape(layout->highlight);
- }
-
- static void DrawChangedLayout(LayoutEditPtr layout)
- {
- HideHighlight(layout);
-
- #if BOUNDS
- SetBounds(layout);
- #endif
-
- DrawDifference(layout);
-
- layout->flags |= highlightOutOfDate;
- ShowHighlight(layout);
- }
-
- static void CopySelection(LayoutEditPtr layout)
- {
- SelectionType selectionType = GetSelectionType(layout->selection);
-
- switch (selectionType)
- {
- case emptySelection:
- case simpleCaret:
- case discontiguousRange:
- break;
-
- case simpleRange:
- {
- SelectionRanges *ranges = &layout->selectionRanges;
- SelectionOffsetRange *pRange;
-
- (void) GetRangeSelection(layout->selection, ranges);
- pRange = ranges->ranges;
-
- layout->scrap = GXGetLayoutShapeParts(layout->layout, pRange->minOffset, pRange->maxOffset, layout->scrap);
-
- break;
- }
- }
- }
-
- static void PasteSelection(LayoutEditPtr layout)
- {
- SelectionType selectionType = GetSelectionType(layout->selection);
- SelectionOffset newCaret, startOffset, endOffset;
-
- SetEraser(layout);
-
- switch (selectionType)
- {
- case emptySelection:
- case discontiguousRange:
- return;
-
- case simpleCaret:
- newCaret = startOffset = endOffset = GetCaretSelection(layout->selection, nil);
- break;
-
- case simpleRange:
- {
- SelectionRanges *ranges = &layout->selectionRanges;
-
- (void) GetRangeSelection(layout->selection, ranges);
- startOffset = ranges->ranges[0].minOffset;
- endOffset = ranges->ranges[0].maxOffset;
- newCaret = startOffset;
-
-
- break;
- }
-
- }
- newCaret += GXGetLayout(layout->scrap, nil, 0, nil, nil, 0, nil, nil, nil, nil);
- GXSetLayoutShapeParts(layout->layout, startOffset, endOffset, layout->scrap);
-
- #if BOUNDS
- SetBounds(layout);
- #endif
-
- DrawDifference(layout);
- NewSelection(layout, newCaret, newCaret);
- }
-
- static void AdjustSelectedLevels(LayoutEditPtr layout, short levelAdjust)
- {
- short *lengths, *levels;
- long levelRunCount;
- SelectionType selectionType = GetSelectionType(layout->selection);
- SelectionRanges *ranges = &layout->selectionRanges;
- SelectionOffset startOffset, endOffset;
-
- UpdateLayout(layout);
-
- switch (selectionType)
- {
- case emptySelection:
- case discontiguousRange:
- return;
-
- case simpleCaret:
- startOffset = endOffset = GetCaretSelection(layout->selection, nil);
- break;
-
- case simpleRange:
- {
- SelectionRanges *ranges = &layout->selectionRanges;
-
- GetRangeSelection(layout->selection, ranges);
- startOffset = ranges->ranges[0].minOffset;
- endOffset = ranges->ranges[0].maxOffset;
- }
- break;
- }
-
- GXGetLayoutParts(layout->layout, startOffset, endOffset, nil, nil, nil, nil, &levelRunCount, nil, nil);
-
- levels = (short *) NewPtr(levelRunCount * sizeof(short));
- lengths = (short *) NewPtr(levelRunCount * sizeof(short));
-
- GXGetLayoutParts(layout->layout, startOffset, endOffset, nil, nil, nil, nil, nil, lengths, levels);
-
- if (startOffset == endOffset) layout->insertionLevel = MAX(*levels + levelAdjust, 0);
- else
- {
- short i, length = endOffset - startOffset, *pl;
-
- SetEraser(layout);
-
- for (pl = levels, i = levelRunCount - 1; i >= 0; --i, ++pl)
- *pl = MAX(*pl + levelAdjust, 0);
-
-
- GXSetLayoutParts(
- layout->layout,
- startOffset,
- endOffset,
- 0,
- nil,
- nil,
- 0,
- nil,
- nil,
- levelRunCount,
- lengths,
- levels);
-
- HideHighlight(layout);
-
- #if BOUNDS
- SetBounds(layout);
- #endif
-
- DrawDifference(layout);
- ShowHighlight(layout);
-
- layout->insertionLevel = -1;
- }
-
- DisposePtr((Ptr) lengths);
- DisposePtr((Ptr) levels);
- }
-
-
- /*
- P U B L I C R O U T I N E S
- */
-
- LayoutEditHandle LayoutEditHandleFromLayout(gxShape layoutShape)
- {
- LayoutEditHandle handle;
- LayoutEditPtr layout;
- #if BOUNDS
- gxRectangle bounds;
- #endif
-
- /* SetShapeFastXorTransfer(layoutShape, nil, nil); */
-
- handle = (LayoutEditHandle) NewHandle(
- sizeof(LayoutEditRecord) + maxRanges * sizeof(SelectionOffsetRange));
-
- layout = LockEditHandle(handle);
- layout->layout = layoutShape;
- layout->eraser = nil;
- layout->flags = 0;
- layout->selection = nil;
- layout->highlight = nil;
- layout->scrap = nil;
- layout->highlightHideCount = 0;
- layout->nextUpdateTime = 0;
- layout->nextBlinkTime = 0;
- layout->textBufferOffset = 0;
- layout->insertionStyle = nil;
- layout->insertionLevel = -1;
- layout->deleteStartOffset = -1;
-
- #if BOUNDS
- layout->boundsEraser = nil;
- GXGetShapeTypographicBounds(layoutShape, &bounds);
- layout->bounds = GXNewRectangle(&bounds);
- GXSetShapeFill(layout->bounds, gxClosedFrameFill);
- #endif
-
- /* set the initial selection to a caret before the first character */
- NewSelectionAndHighlight(layout, 0, 0);
-
- UnlockHandle(handle);
-
- return handle;
- }
-
- LayoutEditHandle NewLayoutEditHandle(
- long textRunCount,
- const short textRunLengths[],
- const void *text[],
- long styleRunCount,
- const short styleRunLengths[],
- const gxStyle styles[],
- long levelRunCount,
- const short levelRunLengths[],
- const short levels[],
- gxLayoutOptions *layoutOptions,
- gxPoint *position,
- gxStyle defaultStyle)
- {
- gxShape layoutShape;
-
- /* just call GXNewLayout for param error checking */
- layoutShape = GXNewLayout(
- textRunCount,
- textRunLengths,
- text,
- styleRunCount,
- styleRunLengths,
- styles,
- levelRunCount,
- levelRunLengths,
- levels,
- layoutOptions,
- position);
-
- /* If GXNewLayout posts an error, we won't get here... */
-
- if (defaultStyle) GXSetShapeStyle(layoutShape, defaultStyle);
- return LayoutEditHandleFromLayout(layoutShape);
- }
-
- long GetLayoutEditHandle(
- LayoutEditHandle handle,
- void *text,
- long *styleRunCount,
- short styleRunLengths[],
- gxStyle styles[],
- long *levelRunCount,
- short levelRunLengths[],
- short levels[],
- gxLayoutOptions *layoutOptions,
- gxPoint *position)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
- long result;
-
- UpdateLayout(layout);
-
- result = GXGetLayout(
- layout->layout,
- text,
- styleRunCount,
- styleRunLengths,
- styles,
- levelRunCount,
- levelRunLengths,
- levels,
- layoutOptions,
- position);
-
- UnlockHandle(handle);
-
- return result;
- }
-
- void SetLayoutEditHandle(
- LayoutEditHandle handle,
- long textRunCount,
- const short textRunLengths[],
- const void *text[],
- long styleRunCount,
- const short styleRunLengths[],
- const gxStyle styles[],
- long levelRunCount,
- const short levelRunLengths[],
- const short levels[],
- const gxLayoutOptions *layoutOptions,
- const gxPoint *position)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- SetEraser(layout);
-
- UpdateLayout(layout);
-
- GXSetLayout(
- layout->layout,
- textRunCount,
- textRunLengths,
- text,
- styleRunCount,
- styleRunLengths,
- styles,
- levelRunCount,
- levelRunLengths,
- levels,
- layoutOptions,
- position);
-
- DrawChangedLayout(layout);
-
- UnlockHandle(handle);
- }
-
- void SetLayoutEditHandleParts(
- LayoutEditHandle handle,
- gxByteOffset oldStartOffset,
- gxByteOffset oldEndOffset,
- long newTextRunCount,
- const short newTextRunLengths[],
- const void *newText[],
- long newStyleRunCount,
- const short newStyleRunLengths[],
- const gxStyle newStyles[],
- long newLevelRunCount,
- const short newLevelRunLengths[],
- const short newLevels[])
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- SetEraser(layout);
-
- UpdateLayout(layout);
-
- GXSetLayoutParts(
- layout->layout,
- oldStartOffset,
- oldEndOffset,
- newTextRunCount,
- newTextRunLengths,
- newText,
- newStyleRunCount,
- newStyleRunLengths,
- newStyles,
- newLevelRunCount,
- newLevelRunLengths,
- newLevels);
-
- DrawChangedLayout(layout);
-
- UnlockHandle(handle);
- }
-
- void SetLayoutEditHandleSelectedParts(
- LayoutEditHandle handle,
- long newTextRunCount,
- const short newTextRunLengths[],
- const void *newText[],
- long newStyleRunCount,
- const short newStyleRunLengths[],
- const gxStyle newStyles[],
- long newLevelRunCount,
- const short newLevelRunLengths[],
- const short newLevels[])
- {
- LayoutEditPtr layout;
- SelectionOffset startOffset, endOffset;
-
- layout = LockEditHandle(handle);
- UpdateLayout(layout);
-
- DisposeStyleAt(&layout->insertionStyle);
- layout->insertionLevel = -1;
-
- switch (GetSelectionType(layout->selection))
- {
- case emptySelection:
- case discontiguousRange:
- /* should never happen */
- break;
-
- case simpleCaret:
- startOffset = endOffset = GetCaretSelection(layout->selection, nil);
-
- if (newTextRunCount == 0)
- {
- if (newStyleRunCount == 1 && newStyleRunLengths[0] == 0)
- {
- layout->insertionStyle = GXCloneStyle(newStyles[0]);
- newStyleRunCount = 0;
- newStyleRunLengths = nil;
- newStyles = nil;
- }
-
- if (newLevelRunCount == 1 && newLevelRunLengths[0] == 0)
- {
- layout->insertionLevel = newLevels[0];
- newLevelRunCount = 0;
- newLevelRunLengths = nil;
- newLevels = nil;
- }
- }
-
- break;
-
- case simpleRange:
- {
- SelectionRanges *ranges = &layout->selectionRanges;
-
- (void) GetRangeSelection(layout->selection, ranges);
-
- startOffset = ranges->ranges[0].minOffset;
- endOffset = ranges->ranges[0].maxOffset;
-
- break;
- }
- }
-
-
- if (newTextRunCount > 0 || newStyleRunCount > 0 || newLevelRunCount > 0)
- {
- SetEraser(layout);
-
- GXSetLayoutParts(
- layout->layout,
- startOffset,
- endOffset,
- newTextRunCount, newTextRunLengths, newText,
- newStyleRunCount, newStyleRunLengths, newStyles,
- newLevelRunCount, newLevelRunLengths, newLevels);
-
- DrawChangedLayout(layout);
- }
-
- UnlockEditHandle(handle);
- }
-
- void SetLayoutEditHandleShapeParts(
- LayoutEditHandle handle,
- gxByteOffset startOffset,
- gxByteOffset endOffset,
- gxShape insert)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- SetEraser(layout);
-
- UpdateLayout(layout);
-
- GXSetLayoutShapeParts(
- layout->layout,
- startOffset,
- endOffset,
- insert);
-
- DrawChangedLayout(layout);
-
- UnlockHandle(handle);
- }
-
- long GetLayoutEditHandleParts(
- LayoutEditHandle handle,
- gxByteOffset startOffset,
- gxByteOffset endOffset,
- void *text,
- long *styleRunCount,
- short styleRunLengths[],
- gxStyle styles[],
- long *levelRunCount,
- short levelRunLengths[],
- short levels[])
- {
- LayoutEditPtr layout = LockEditHandle(handle);
- long result;
-
- UpdateLayout(layout);
-
- result = GXGetLayoutParts(
- layout->layout,
- startOffset,
- endOffset,
- text,
- styleRunCount,
- styleRunLengths,
- styles,
- levelRunCount,
- levelRunLengths,
- levels);
-
- UnlockHandle(handle);
- return result;
- }
-
- long GetLayoutEditHandleSelectedParts(
- LayoutEditHandle handle,
- void *text,
- long *styleRunCount,
- short styleRunLengths[],
- gxStyle styles[],
- long *levelRunCount,
- short levelRunLengths[],
- short levels[])
- {
- SelectionType selectionType;
- gxByteOffset endOffset, startOffset;
- LayoutEditPtr layout;
- long result;
-
- layout = LockEditHandle(handle);
- UpdateLayout(layout);
- selectionType = GetSelectionType(layout->selection);
-
- switch (selectionType)
- {
- case emptySelection:
- case discontiguousRange:
- /* should never happen */
- break;
-
- case simpleCaret:
-
- startOffset = endOffset = GetCaretSelection(layout->selection, nil);
-
- if (styles != nil && layout->insertionStyle != nil)
- {
- *styles = layout->insertionStyle;
- styles = nil;
- }
-
- if (levels != nil && layout->insertionLevel >= 0)
- {
- *levels = layout->insertionLevel;
- levels = nil;
- }
-
- break;
-
- case simpleRange:
- {
- SelectionRanges *ranges = &layout->selectionRanges;
- // short length;
-
- (void) GetRangeSelection(layout->selection, ranges);
-
- startOffset = ranges->ranges[0].minOffset;
- endOffset = ranges->ranges[0].maxOffset;
- }
-
- }
-
- result = GXGetLayoutParts(
- layout->layout,
- startOffset,
- endOffset,
- text,
- styleRunCount,
- styleRunLengths,
- styles,
- levelRunCount,
- levelRunLengths,
- levels);
-
- UnlockHandle(handle);
- return result;
- }
-
- gxShape GetLayoutEditHandleShapeParts(
- LayoutEditHandle handle,
- gxByteOffset startOffset,
- gxByteOffset endOffset,
- gxShape dest)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
- gxShape result;
-
- UpdateLayout(layout);
-
- result = GXGetLayoutShapeParts(layout->layout, startOffset, endOffset, dest);
-
- UnlockHandle(handle);
- return result;
- }
-
- void LayoutEditRotateShape(LayoutEditHandle handle, Fixed degrees, Fixed translateX, Fixed translateY)
- {
- LayoutEditPtr layout;
-
- layout = LockEditHandle(handle);
-
- UpdateLayout(layout);
-
- SetEraser(layout);
-
- GXRotateShape(layout->layout, degrees, translateX, translateY);
-
- DrawChangedLayout(layout);
-
- UnlockEditHandle(handle);
- }
-
- void LayoutEditIdle(LayoutEditHandle handle)
- {
- ulong ticks = TickCount();
- ulong nextUpdateTime = ((LayoutEditPtr) *handle)->nextUpdateTime;
- ulong nextBlinkTime = ((LayoutEditPtr) *handle)->nextBlinkTime;
-
- if ((nextUpdateTime != 0) && (ticks >= nextUpdateTime))
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- HideHighlight(layout);
- UpdateLayout(layout);
- ShowHighlight(layout);
-
- UnlockEditHandle(handle);
- }
-
- if (((LayoutEditPtr) *handle)->flags & highlightBlinks)
- {
- if (ticks >= nextBlinkTime)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- if (layout->flags & highlightIsBlinking)
- {
- UpdateLayout(layout);
- ShowHighlight(layout);
- }
- else
- {
- HideHighlight(layout);
- }
-
- layout->flags ^= highlightIsBlinking;
-
- layout->nextBlinkTime = ticks + GetCaretTime();
-
- UnlockEditHandle(handle);
- }
- }
- }
-
- void LayoutEditClick(LayoutEditHandle handle, gxPoint hitDown, Boolean extend)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
- gxPoint lastPoint = hitDown;
- SelectionOffset firstHitOffset, lastHitOffset;
- gxLayoutHitInfo hitInfo;
- Boolean oldIsCaret, newIsCaret = true;
- gxShape diffHighlight = nil, oldHighlight = nil;
- gxViewPort layoutViewPort = GetShapeViewPort(layout->layout);
-
- /* get the offset for the hit down gxPoint */
- GXHitTestLayout(layout->layout, &hitDown, gxHighlightAverageAngle, &hitInfo, nil);
-
- if (extend)
- {
- Boolean extendLeft;
- SelectionOffset oldFirstOffset, oldLastOffset;
-
- switch (GetSelectionType(layout->selection))
- {
- case emptySelection:
- case discontiguousRange:
- oldFirstOffset = oldLastOffset = (SelectionOffset) hitInfo.hitSideOffset;
- break;
-
- case simpleCaret:
- oldFirstOffset = oldLastOffset = GetCaretSelection(layout->selection, nil);
- break;
-
- case simpleRange:
- {
- SelectionRanges *ranges = &layout->selectionRanges;
-
- (void) GetRangeSelection(layout->selection, ranges);
- oldFirstOffset = ranges->ranges[0].minOffset;
- oldLastOffset = ranges->ranges[0].maxOffset;
- break;
- }
- }
-
- if (hitInfo.hitSideOffset <= oldFirstOffset)
- extendLeft = true;
- else if (hitInfo.hitSideOffset >= oldLastOffset)
- extendLeft = false;
- else
- extendLeft = ((hitInfo.hitSideOffset - oldFirstOffset) <= (oldLastOffset - hitInfo.hitSideOffset));
-
- if (extendLeft)
- {
- firstHitOffset = (SelectionOffset) hitInfo.hitSideOffset;
- lastHitOffset = oldLastOffset;
- }
- else
- {
- firstHitOffset = oldFirstOffset;
- lastHitOffset = (SelectionOffset) hitInfo.hitSideOffset;
- }
- }
- else
- firstHitOffset = lastHitOffset = (SelectionOffset) hitInfo.hitSideOffset;
-
- /* erase the old highlight */
- ResetCaret(layout);
- DrawHighlight(layout);
-
- /* recompute the selection and highlight while the mouse button is still down */
- while (Button())
- {
- GXGetViewPortMouse(layoutViewPort, &hitDown);
-
- /* continue if the mouse hasn't moved */
- if (hitDown.x == lastPoint.x && hitDown.y == lastPoint.y)
- continue;
-
- lastPoint = hitDown;
- GXHitTestLayout(layout->layout, &hitDown, gxHighlightAverageAngle, &hitInfo, nil);
-
- /* continue if the selection hasn't changed */
- if (hitInfo.hitSideOffset == lastHitOffset) continue;
-
- oldIsCaret = newIsCaret;
-
- /* save the old highlight and calculate the new one */
- lastHitOffset = (SelectionOffset) hitInfo.hitSideOffset;
- newIsCaret = (lastHitOffset == firstHitOffset);
-
- if (oldIsCaret || newIsCaret)
- {
- if (!oldIsCaret)
- DrawHighlight(layout);
- if (!newIsCaret)
- {
- NewSelectionAndHighlight(layout, firstHitOffset, lastHitOffset);
- DrawHighlight(layout);
- }
- }
- else
- {
- oldHighlight = GXCopyToShape(oldHighlight, layout->highlight);
- NewSelectionAndHighlight(layout, firstHitOffset, lastHitOffset);
-
- /* to reduce flicker, draw the difference between the new and old highlight */
- diffHighlight = GXCopyToShape(diffHighlight, layout->highlight);
- GXExcludeShape(diffHighlight, oldHighlight);
- if (layout->highlightHideCount <= 0)
- GXDrawShape(diffHighlight);
- }
- }
-
- if (newIsCaret)
- {
- ResetCaret(layout);
- NewSelectionAndHighlight(layout, firstHitOffset, lastHitOffset);
- DrawHighlight(layout);
- }
-
- UnlockEditHandle(handle);
-
- DisposeShapeAt(&diffHighlight);
- DisposeShapeAt(&oldHighlight);
- }
-
-
- void LayoutEditActivate(LayoutEditHandle handle)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- if (layout->oldScript != GetScriptManagerVariable(smKeyScript))
- KeyScript(layout->oldScript);
-
- UpdateLayout(layout);
- ShowHighlight(layout);
- UnlockEditHandle(handle);
- }
-
-
- void LayoutEditDeactivate(LayoutEditHandle handle)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- layout->oldScript = GetScriptManagerVariable(smKeyScript);
-
- HideHighlight(layout);
- UnlockEditHandle(handle);
- }
-
-
- void LayoutEditKey(LayoutEditHandle handle, char key)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- switch (key)
- {
- case leftArrow:
- case rightArrow:
- {
- SelectionOffset newCaret;
-
- HideHighlight(layout);
- UpdateLayout(layout);
-
- if (key == leftArrow)
- newCaret = GXGetLeftVisualOffset(
- layout->layout,
- layout->selectionRanges.ranges[0].minOffset);
- else newCaret = GXGetRightVisualOffset(
- layout->layout,
- layout->selectionRanges.ranges[0].maxOffset);
-
- NewSelection(layout, newCaret, newCaret);
- ResetCaret(layout);
- ShowHighlight(layout);
- break;
- }
-
- case backSpace:
- {
- DeleteSelection(layout);
- if (layout->nextUpdateTime == 0)
- layout->nextUpdateTime = TickCount() + nextUpdateDelta;
- break;
- }
-
- default:
- {
-
- switch (GetSelectionType(layout->selection))
- {
- case emptySelection:
- break;
-
- case discontiguousRange:
- case simpleRange:
- DeleteSelection(layout);
-
- /* fall through to simpleCaret case */
-
- case simpleCaret:
- InsertByte(layout, key);
- if (layout->nextUpdateTime == 0)
- layout->nextUpdateTime = TickCount() + nextUpdateDelta;
- }
- }
- }
-
- UnlockEditHandle(handle);
- }
-
-
- void LayoutEditUpdate(LayoutEditHandle handle)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- GXDrawShape(layout->layout);
-
- #if BOUNDS
- GXDrawShape(layout->bounds);
- #endif
-
- DrawHighlight(layout);
-
- UnlockEditHandle(handle);
- }
-
-
- SelectionHandle LayoutEditGetSelection(LayoutEditHandle handle)
- {
- LayoutEditPtr layout = (LayoutEditPtr) LockHandle(handle);
- SelectionHandle selection;
-
- UpdateLayout(layout);
- selection = layout->selection;
- UnlockEditHandle(handle);
-
- return selection;
- }
-
- void LayoutEditSetSelection(LayoutEditHandle handle, SelectionOffset start, SelectionOffset end)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- UpdateLayout(layout);
-
- HideHighlight(layout);
- NewSelection(layout, start, end);
- ShowHighlight(layout);
-
- UnlockEditHandle(handle);
- }
-
- void LayoutEditSetSelectionHandle(LayoutEditHandle handle, SelectionHandle selection)
- {
- SelectionOffset end, start;
-
- switch (GetSelectionType(selection))
- {
- case emptySelection:
- case discontiguousRange:
- return;
-
- case simpleCaret:
- start = end = GetCaretSelection(selection, nil);
- break;
-
- case simpleRange:
- {
- SelectionRanges ranges;
-
- (void) GetRangeSelection(selection, &ranges);
- start = ranges.ranges[0].minOffset;
- end = ranges.ranges[0].maxOffset;
- break;
- }
-
- }
-
- LayoutEditSetSelection(handle, start, end);
- }
-
- gxViewPort GetLayoutEditViewPort(LayoutEditHandle handle)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
- gxViewPort viewPort = GetShapeViewPort(layout->layout);
-
- UnlockEditHandle(handle);
- return viewPort;
- }
-
- void LayoutEditSetStyle(LayoutEditHandle handle, gxStyle newStyle)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
- SelectionType selectionType = GetSelectionType(layout->selection);
-
- UpdateLayout(layout);
-
- DisposeStyleAt(&layout->insertionStyle);
-
- switch (selectionType)
- {
- case emptySelection:
- case discontiguousRange:
- /* should never happen */
- break;
-
- case simpleCaret:
- layout->insertionStyle = GXCloneStyle(newStyle);
- break;
-
- case simpleRange:
- {
- SelectionRanges *ranges = &layout->selectionRanges;
- SelectionOffset startOffset, endOffset;
- short length;
-
- SetEraser(layout);
-
- (void) GetRangeSelection(layout->selection, ranges);
-
- startOffset = ranges->ranges[0].minOffset;
- endOffset = ranges->ranges[0].maxOffset;
- length = endOffset - startOffset;
-
- GXSetLayoutParts(
- layout->layout,
- startOffset,
- endOffset,
- 0,
- nil,
- nil,
- 1,
- &length,
- &newStyle,
- 0,
- nil,
- nil);
-
- DrawChangedLayout(layout);
-
- break;
- }
- }
-
- UnlockEditHandle(handle);
- }
-
- void LayoutEditIncrementLevel(LayoutEditHandle handle)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- HideHighlight(layout);
- AdjustSelectedLevels(layout, 1);
- layout->flags |= highlightOutOfDate;
- ShowHighlight(layout);
-
- UnlockEditHandle(handle);
- }
-
- void LayoutEditDecrementLevel(LayoutEditHandle handle)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- HideHighlight(layout);
- AdjustSelectedLevels(layout, -1);
- layout->flags |= highlightOutOfDate;
- ShowHighlight(layout);
-
- UnlockEditHandle(handle);
- }
-
- void LayoutEditSetLevel(LayoutEditHandle handle, long level)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
- SelectionType selectionType = GetSelectionType(layout->selection);
- short newLevel = level;
-
- UpdateLayout(layout);
-
- switch (selectionType)
- {
- case emptySelection:
- case discontiguousRange:
- /* should never happen */
- break;
-
- case simpleCaret:
- layout->insertionLevel = newLevel;
- break;
-
- case simpleRange:
- {
- SelectionRanges *ranges = &layout->selectionRanges;
- SelectionOffset startOffset, endOffset;
- short length;
-
- SetEraser(layout);
-
- (void) GetRangeSelection(layout->selection, ranges);
-
- startOffset = ranges->ranges[0].minOffset;
- endOffset = ranges->ranges[0].maxOffset;
- length = endOffset - startOffset;
-
- GXSetLayoutParts(
- layout->layout,
- startOffset,
- endOffset,
- 0,
- nil,
- nil,
- 0,
- nil,
- nil,
- 1,
- &length,
- &newLevel);
-
- #if BOUNDS
- SetBounds(layout);
- #endif
-
- HideHighlight(layout);
- DrawDifference(layout);
- layout->flags |= highlightOutOfDate;
- ShowHighlight(layout);
-
- layout->insertionLevel = -1;
- break;
- }
-
- }
-
- UnlockEditHandle(handle);
- }
-
- void LayoutEditCut(LayoutEditHandle handle)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
- SelectionType selectionType = GetSelectionType(layout->selection);
-
- if (selectionType != emptySelection && selectionType != simpleCaret)
- {
- CopySelection(layout);
- DeleteSelection(layout);
- HideHighlight(layout);
- UpdateLayout(layout);
- ShowHighlight(layout);
- }
-
- UnlockEditHandle(handle);
- }
-
- void LayoutEditCopy(LayoutEditHandle handle)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- CopySelection(layout);
-
- UnlockEditHandle(handle);
- }
-
- void LayoutEditPaste(LayoutEditHandle handle)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- HideHighlight(layout);
- PasteSelection(layout);
- ShowHighlight(layout);
-
- UnlockEditHandle(handle);
- }
-
- void LayoutEditClear(LayoutEditHandle handle)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- DeleteSelection(layout);
- HideHighlight(layout);
- UpdateLayout(layout);
- ShowHighlight(layout);
-
- UnlockEditHandle(handle);
- }
-
- void LayoutEditFromScrap(LayoutEditHandle handle)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
- long offset, length;
- Handle buffer = NewHandle(0);
-
- if (GetScrap(buffer, 'FLAY', &offset) > 0)
- {
- long portCount = GXGetShapeViewPorts(GXGetDefaultShape(gxLayoutType), nil);
- gxViewPort *ports = (gxViewPort *) NewPtr(portCount * sizeof(gxViewPort));
-
- GXGetShapeViewPorts(GXGetDefaultShape(gxLayoutType), ports);
- DisposeShapeAt(&layout->scrap);
-
- layout->scrap = HandleToShape(buffer, portCount, ports);
- DisposePtr((Ptr) ports);
- }
- else if ((length = GetScrap(buffer, 'TEXT', &offset)) > 0)
- {
- void *text = (void *) LockHandle(buffer);
- short runLength = length;
- gxStyle defaultStyle = GXGetShapeStyle(layout->layout);
- short level0 = 0;
-
- DisposeShapeAt(&layout->scrap);
- layout->scrap = GXNewLayout(
- 1,
- &runLength,
- (const void **) &text,
- 1,
- &runLength,
- &defaultStyle,
- 1,
- &runLength,
- &level0,
- nil,
- nil);
-
- }
-
- DisposeHandle(buffer);
-
- UnlockEditHandle(handle);
- }
-
- void LayoutEditToScrap(LayoutEditHandle handle)
- {
- LayoutEditPtr layout = LockEditHandle(handle);
-
- ZeroScrap();
-
- if (layout->scrap)
- {
- long textLength;
- Ptr textPtr;
- Handle shapeHandle = ShapeToHandle(layout->scrap);
-
-
- textLength = GXGetLayout(layout->scrap, nil, nil, nil, nil, nil, nil, nil, nil, nil);
- textPtr = NewPtr(textLength);
- GXGetLayout(layout->scrap, (void *) textPtr, nil, nil, nil, nil, nil, nil, nil, nil);
-
- PutScrap(GetHandleSize(shapeHandle), 'FLAY', LockHandle(shapeHandle));
- PutScrap(textLength, 'TEXT', textPtr);
-
- DisposeShapeAt(&layout->scrap);
- DisposePtr(textPtr);
- DisposeHandle(shapeHandle);
- }
-
- UnlockEditHandle(handle);
- }
-
-
- void DisposeLayoutEditHandle(LayoutEditHandle handle)
- {
- LayoutEditPtr layout = (LayoutEditPtr) LockHandle(handle);
-
- #if BOUNDS
- DisposeShapeAt(&layout->bounds);
- DisposeShapeAt(&layout->boundsEraser);
- #endif
-
- DisposeShapeAt(&layout->layout);
- DisposeShapeAt(&layout->eraser);
- DisposeShapeAt(&layout->highlight);
- DisposeShapeAt(&layout->scrap);
- DisposeStyleAt(&layout->insertionStyle);
- DisposeSelection(layout->selection);
- DisposeHandle(handle);
- }
-